package com.promis.okhttp;

import android.content.Context;
import android.os.Handler;
import android.util.Log;

import com.promis.util.FileUtils;
import com.promis.util.NetworkUtils;
import com.promis.util.StringUtils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.Cookie;
import okhttp3.CookieJar;
import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

/**
 * Created by jidanbo on 2018/1/31.
 */

public abstract class HttpDownloadClient {
    private Context context;
    private static OkHttpClient.Builder builder = null;
    private static Handler handler;
    private String saveFileName;

    public HttpDownloadClient(Context context, String saveFileName) {
        this.context = context;
        this.saveFileName = saveFileName;

        if (builder == null) {
            builder = new OkHttpClient.Builder()
                    .cookieJar(new CookieJar() {
                        private final HashMap<String, List<Cookie>> cookieStore = new HashMap<>();

                        @Override
                        public void saveFromResponse(HttpUrl httpUrl, List<Cookie> list) {
                            cookieStore.put(httpUrl.url().getHost(), list);
                        }

                        @Override
                        public List<Cookie> loadForRequest(HttpUrl httpUrl) {
                            List<Cookie> cookies = cookieStore.get(httpUrl.url().getHost());
                            return cookies != null ? cookies : new ArrayList<Cookie>();
                        }
                    })
                    .connectTimeout(10, TimeUnit.SECONDS)
                    .readTimeout(10, TimeUnit.SECONDS)
                    .writeTimeout(30, TimeUnit.SECONDS);
        }

        if (handler == null) handler = new Handler();
    }

    public void postAsyn(String url, HttpStringParams params, final ProgressResponseListener progressResponseListener) {
        OkHttpClient client = addInterceptors(progressResponseListener);
        RequestBody requestBody = params.getBuilder().build();
        enqueue(client, newRequestBuilder(url).post(requestBody).build());
    }

    public void getAsyn(String url, ProgressResponseListener progressResponseListener) {
        OkHttpClient client = addInterceptors(progressResponseListener);
        enqueue(client, newRequestBuilder(url).get().build());
    }

    private OkHttpClient addInterceptors(final ProgressResponseListener progressResponseListener) {
        if (!builder.networkInterceptors().isEmpty()) builder.networkInterceptors().clear();
        builder.networkInterceptors().add(new Interceptor() {
            @Override
            public Response intercept(Chain chain) throws IOException {
                //拦截
                Response originalResponse = chain.proceed(chain.request());
                //包装响应体并返回
                return originalResponse.newBuilder()
                        .body(new ProgressResponseBody(originalResponse.body(), progressResponseListener))
                        .build();
            }
        });
        return builder.build();
    }

    private void enqueue(OkHttpClient client, Request request) {
        if (NetworkUtils.isNetworkConnected(context)) {
            client.newCall(request).enqueue(newCallback());
        } else onNetworkDisconnect();
    }

    private Request.Builder newRequestBuilder(String url) {
        return new Request.Builder().url(url).addHeader("X-Client-Type", "Android").addHeader("AcceptType", "json").addHeader("ParamType", "form");
    }

    private Callback newCallback() {
        return new Callback() {

            @Override
            public void onFailure(Call call, final IOException e) {
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        onError("连接异常，请稍后重试!");
                        onFinish();
                    }
                });
            }

            @Override
            public void onResponse(Call call, final Response response) throws IOException {
                if (response.isSuccessful()) {
                    final byte[] responseBody = response.body().bytes();
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            handleResponse(responseBody);
                            onFinish();
                        }
                    });
                } else {
                    onError("响应异常：" + response.code() + "," + response.message());
                    onFinish();
                }
            }
        };
    }

    private void handleResponse(byte[] responseBody) {
        FileOutputStream fileOutputStream = null;
        try {
            File file = FileUtils.getDownloadFile(context, saveFileName);
            fileOutputStream = new FileOutputStream(file);
            fileOutputStream.write(responseBody);
            onSuccess(file);
        } catch (Exception ex) {
            if (ex != null && !StringUtils.isNullOrEmpty(ex.getMessage())) {
                Log.e("Response Error: ", ex.getMessage());
            }
            onError("响应数据解析异常" + ex.getMessage());
        } finally {
            if (fileOutputStream != null) try {fileOutputStream.close(); } catch (IOException ex) {}
        }
    }

    public Context getContext() {
        return context;
    }

    protected abstract void onSuccess(File file);

    protected void onError(String errorMsg) {}

    protected void onFinish(){}

    protected void onNetworkDisconnect(){}
}
